package com.company.eos.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import com.company.eos.common.BusinessException;
import com.company.eos.common.ErrorEnum;
import com.company.eos.common.GlobalConstant;
import com.company.eos.common.R;
import com.company.eos.common.util.*;
import com.company.eos.controller.form.user.*;
import com.company.eos.service.LoginAuthorService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.Range;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.company.eos.domain.User;
import com.company.eos.service.UserService;

import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Set;

/**
 * @author: Song, Wei
 * @date: 2022-01-12
 */
@Slf4j
@RestController
@RequestMapping("/user")
@Tag(name = "用户模块Web接口", description = "")
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private LoginAuthorService loginAuthorService;

    /**
     * 登陆成功后加载用户的基本信息
     */
    @GetMapping("/loadUserInfo")
    @Operation(summary = "登陆成功后加载用户的基本信息")
    @SaCheckLogin
    public R loadUserInfo() {
        log.info("登陆成功后加载用户的基本信息");
        int userId = StpUtil.getLoginIdAsInt();
        HashMap summary = userService.searchUserSummary(userId);
        return R.ok(summary);
    }

    @PostMapping("/searchById")
    @Operation(summary = "根据ID查找用户")
    @SaCheckPermission(value = {"ROOT", "USER:SELECT"}, mode = SaMode.OR)
    public R searchById(@Valid @RequestBody SearchUserByIdForm form) {
        log.info("根据ID查找用户，参数：{}", form);
        HashMap map = userService.searchById(form.getUserId());
        return R.ok(map);
    }

    @GetMapping("/searchAllUser")
    @Operation(summary = "查询所有用户")
    @SaCheckLogin
    public R searchAllUser() {
        log.info("查询所有用户");
        ArrayList<HashMap> list = userService.searchAllUser();
        return R.ok().put("list", list);
    }

    @PostMapping("/login")
    @Operation(summary = "登陆系统")
    public R login(@RequestBody LoginForm form) {
        log.info("用户请求登录，参数：{}", form);
        // 弃用登录逻辑： Integer userId = userService.login(param);
        User login = loginAuthorService.login(form);
        Integer userId = login.getId();

        // 如果查询到用户ID返回true
        R r = R.ok().put("result", userId != null);

        // 查询用户权限列表
        if (userId != null) {
            StpUtil.setLoginId(userId);
            Set<String> permissions = userService.searchUserPermissions(userId);
            /*
             * 因为新版Chrome不支持前端Ajax的withCredentials，
             * 导致Ajax无法提交Cookie，所以要取出生成的Token返回给前端
             * 让前端保存在Storage中，然后每次在Ajax的Header上提交Token
             */
            User user = userService.selectById(userId);
            String token = StpUtil.getTokenInfo().getTokenValue();
            // 添加结果
            r.put("permissions", permissions).put("token", token).put("user", user);
        }
        return r;
    }

    @GetMapping("/logout")
    @Operation(summary = "退出登录")
    public R logout() {
        log.info("退出登录");
        StpUtil.logout();
        return R.ok();
    }

    @PostMapping("/updatePassword")
    @SaCheckLogin
    @Operation(summary = "修改密码")
    public R updatePassword(@Valid @RequestBody UpdatePasswordForm form) {
        log.info("用户修改密码，参数：{}", form);
        // 获取userId
        int userId = StpUtil.getLoginIdAsInt();
        UpdatePasswordDTO dto = new UpdatePasswordDTO(userId, form.getPassword());
        log.info("用户更新密码，参数：{}", dto);
        Integer rows = loginAuthorService.updatePassword(dto);
        // 弃用密码修改逻辑： int rows = userService.updatePassword(param);
        return R.ok().put("rows", rows);
    }

    @PostMapping("/searchUserByPage")
    @Operation(summary = "查询用户分页记录")
    @SaCheckPermission(value = {"ROOT", "USER:SELECT"}, mode = SaMode.OR)
    public R searchUserByPage(@Valid @RequestBody SearchUserByPageForm form) {
        log.info("查询用户分页记录，参数：{}", form);
        @NotNull(message = "page不能为空") @Min(value = 1, message = "page不能小于1") Integer page = form.getPage();
        @NotNull(message = "length不能为空") @Range(min = 10, max = 50, message = "length必须在10～50之间") Integer length = form.getLength();
        int start = (page - 1) * length;
        HashMap param = JSONUtil.parse(form).toBean(HashMap.class);
        param.put("start", start);

        PageUtils pageUtils = userService.searchUserByPage(param);
        return R.ok().put("page", pageUtils);
    }

    @PostMapping("/insert")
    @SaCheckPermission(value = {"ROOT", "USER:INSERT"}, mode = SaMode.OR)
    @Operation(summary = "添加用户")
    public R insert(@Valid @RequestBody InsertUserForm form) {
        log.info("添加用户，参数：{}", form);
        User user = JSONUtil.parse(form).toBean(User.class);
        user.setRoot(false);
        user.setStatus((byte) 1);
        user.setRole(JSONUtil.parseArray(form.getRole()).toString());
        user.setCreateTime(new Date());
        user.setPhoto(GlobalConstant.AVATAR_URL);
        int rows = userService.insert(user);
        User user1 = userService.selectUserByEmail(form.getEmail());
        Integer integer = loginAuthorService.insertLoginAccountByUser(user1);
        return integer >= 1 ? R.ok().put("rows", rows) : R.error();
    }

    @PostMapping("/update")
    @SaCheckPermission(value = {"ROOT", "USER:UPDATE"}, mode = SaMode.OR)
    @Operation(summary = "修改用户")
    public R update(@Valid @RequestBody UpdateUserForm form) {
        log.info("修改用户，参数：{}", form);
        HashMap param = JSONUtil.parse(form).toBean(HashMap.class);
        param.replace("role", JSONUtil.parseArray(form.getRole()).toString());
        int rows = userService.update(param);
        // 修改用户登录密码
        if (rows == 1) {
            UpdateProfileDTO dto = new UpdateProfileDTO(form.getUserId(), form.getTel(), form.getEmail());
            Integer integer = loginAuthorService.updateProfile(dto);
            // 修改密码，只有传了密码才会修改
            if (form.getPassword() != null) {
                Integer i = loginAuthorService.updatePassword(new UpdatePasswordDTO(form.getUserId(), form.getPassword()));
                if (i <= 0) {
                    throw new BusinessException(ErrorEnum.UPDATE_PASSWORD_ERROR);
                }
            }
            if (integer <= 0) {
                throw new BusinessException(ErrorEnum.UPDATE_PASSWORD_ERROR);
            }
            int id = StpUtil.getLoginIdAsInt();
            // 如果当前登录用户与修改的目标用户不一致，则将被修改的用户下线
            if (id != form.getUserId()) {
                StpUtil.logoutByLoginId(form.getUserId());
            }
        }
        return R.ok().put("rows", rows);
    }

    @PostMapping("/deleteUserByIds")
    @SaCheckPermission(value = {"ROOT", "USER:DELETE"}, mode = SaMode.OR)
    @Operation(summary = "删除用户")
    public R deleteUserByIds(@Valid @RequestBody DeleteUserByIdsForm form) {
        log.info("删除用户，参数：{}", form);
        Integer userId = StpUtil.getLoginIdAsInt();
        // 不能删除自己
        if (ArrayUtil.contains(form.getIds(), userId)) {
            return R.error("您不能删除自己的账户");
        }
        int rows = userService.deleteUserByIds(form.getIds());
        @NotEmpty(message = "ids不能为空") Integer[] ids = form.getIds();
        for (Integer id : ids) {
            loginAuthorService.deleteLoginAccountByUserId(id);
        }
        if (rows > 0) {
            for (Integer id : form.getIds()) {
                // 把删除的用户强制踢下线
                StpUtil.logoutByLoginId(id);
            }
        }
        return R.ok().put("rows", rows);
    }

    @PostMapping("/searchNameAndDept")
    @Operation(summary = "查询用户姓名和部门")
    @SaCheckLogin
    public R searchNameAndDept(@Valid @RequestBody SearchUserAndDeptForm form) {
        log.info("查询用户姓名和部门，参数：{}", form);
        return R.ok(userService.searchNameAndDept(form.getId()));
    }

    @PostMapping("/dismissUserByIds")
    @SaCheckPermission(value = {"ROOT", "USER:DELETE"}, mode = SaMode.OR)
    @Operation(summary = "离职用户")
    public R dismissUserByIds(@Valid @RequestBody DeleteUserByIdsForm form) {
        log.info("离职用户，参数：{}", form);
        Integer userId = StpUtil.getLoginIdAsInt();
        // 不能删除自己
        if (ArrayUtil.contains(form.getIds(), userId)) {
            return R.error("您不能让自己离职");
        }
        int rows = userService.dismissUserByIds(form.getIds());
        if (rows > 0) {
            for (Integer id : form.getIds()) {
                // 把删除的用户强制踢下线
                StpUtil.logoutByLoginId(id);
            }
        }
        return R.ok().put("rows", rows);
    }

    @GetMapping("/generatorLoginAccount")
    public R generatorLoginAccount() {
        log.info("生成所有登录账号");
        return R.ok().put("rows", loginAuthorService.generatorLoginAccount());
    }

    @PostMapping("/sendVerify")
    public R sendForgetVerify(@RequestBody String email) {
        log.info("发送忘记密码的验证码，参数：{}", email);
        return R.ok().put("rows", userService.sendVerify(email));
    }

    @PostMapping("/resetPassword")
    public R resetPassword(@RequestBody ResetPasswordDTO dto) {
        log.info("用户重置密码，参数：{}", dto);
        return R.ok().put("rows", userService.resetPassword(dto));
    }

}
